package com.lambda.widgets;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

public class RippleView extends AppCompatImageView {
    private final Paint mPaint;
    private ExecutorService mRunnerServer;
    private RippleRunner mRunner;
    private float mRadius;
    private int mColor;

    public RippleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL);

        TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.RippleView);
        final float width = arr.getDimension(R.styleable.RippleView_rv_ripple_width, 100);
        final int count = arr.getInt(R.styleable.RippleView_rv_ripple_count, 3);
        mRunner = new RippleRunner(width, count);
        mColor = arr.getColor(R.styleable.RippleView_rv_ripple_color, 0) & 0x00ffffff;
        arr.recycle();

        mRunnerServer = Executors.newSingleThreadExecutor();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mRadius = getMeasuredWidth() / 2.f;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mRunnerServer.submit(mRunner);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mRunner.detach();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        mRunner.draw(getMeasuredWidth(), getMeasuredHeight(), canvas);
        super.onDraw(canvas);
    }

    private class RippleRunner implements Runnable {
        private AtomicBoolean detach = new AtomicBoolean(false);
        private Ripple ripple;

        private float mRippleWidth;
        private int mRippleCount;
        private float mStep;

        private RippleRunner(float rippleWidth, int rippleCount) {
            mRippleWidth = rippleWidth;
            mRippleCount = rippleCount;

            mStep = mRippleWidth / mRippleCount;

            ripple = new Ripple();
        }

        @Override
        public void run() {
            long cnt = System.currentTimeMillis();
            long millis = cnt;

            Ripple tr;
            while (!detach.get()) {
                long deltaMillis = cnt - millis;
                if (deltaMillis > 32) {
                    millis = cnt;
                    tr = ripple;

                    do {
                        tr.update(deltaMillis);
                        tr = tr.next;
                    } while (tr != null);

                    postInvalidate();
                }

                cnt = System.currentTimeMillis();
            }
        }

        private void detach() {
            detach.set(true);
        }

        private void draw(int width, int height, @NonNull Canvas canvas) {
            Ripple tr = ripple;
            do {
                int c = (int) (225 * (1 - tr.radius / mRippleWidth));
                c = c << 24 & 0xff000000;
                mPaint.setColor(c + mColor);
                canvas.drawCircle(width / 2.f, height / 2.f, mRadius + tr.radius, mPaint);
                tr = tr.next;
            } while (tr != null);
        }

        private class Ripple {
            private float radius;
            private Ripple next;

            private void update(long delta) {
                radius += mStep * (delta / 1000.f);

                if (count < mRippleCount && radius > mStep && next == null) {
                    count++;
                    next = new Ripple();
                }

                if (radius > mRippleWidth) {
                    radius = 0;
                }
            }
        }
    }

    private int count = 0;
}
